package com.ymx.darling.log.jdbc;

import com.ymx.darling.bean.sql.BoundSql;
import com.ymx.darling.bean.sql.Statement;
import com.ymx.darling.util.ExceptionUtil;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.PreparedStatement;

/**
 * @author 爱Java的小于
 */
public class ConnectionLogger extends BaseJdbcLogger implements InvocationHandler {
    private final Connection connection;
    private final Statement statement;

    public ConnectionLogger(Connection connection, Statement statement) {
        super(statement.getLogger());
        this.connection = connection;
        this.statement = statement;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            if (Object.class.equals(method.getDeclaringClass())) {
                return method.invoke(this, args);

            } else if (!("prepareStatement".equals(method.getName()) || "prepareCall".equals(method.getName()))) {
                return method.invoke(this.connection, args);

            } else {
                if (this.isDebugEnabled()) {
                    BoundSql boundSql = statement.getBoundSql();
                    this.debug("  Preparing: " + boundSql.getSql(), true);
                }

                PreparedStatement stmt = (PreparedStatement)method.invoke(this.connection, args);
                return PreparedStatementLogger.newInstance(stmt, this.getStatementLogger());
            }
        } catch (Throwable var5) {
            throw ExceptionUtil.unwrapThrowable(var5);
        }
    }


    /**
     * 构建一个connection代理实例
     * @param conn connection
     * @param statement statement sql语句
     * @return Connection的代理实例
     */
    public static Connection newInstance(Connection conn, Statement statement) {
        InvocationHandler handler = new ConnectionLogger(conn, statement);
        ClassLoader cl = Connection.class.getClassLoader();
        return (Connection) Proxy.newProxyInstance(cl, new Class[]{Connection.class}, handler);
    }
}
